<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTTP/HTTPS 测试工具</title>
    <!-- 引入外部资源 -->
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.16.0/js/md5.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>

    <!-- Tailwind 配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#165DFF',
                        secondary: '#36CFC9',
                        dark: '#1D2129',
                        light: '#F2F3F5',
                        success: '#52C41A',
                        danger: '#FF4D4F',
                        warning: '#FAAD14'
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                    },
                },
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
      .content-auto { content-visibility: auto; }
      .transition-height { transition: max-height 0.3s ease-in-out; }
      .text-shadow { text-shadow: 0 1px 2px rgba(0,0,0,0.1); }
      .scrollbar-thin { scrollbar-width: thin; }
      .scrollbar-thin::-webkit-scrollbar { width: 6px; height: 6px; }
      .scrollbar-thin::-webkit-scrollbar-thumb { background-color: rgba(156, 163, 175, 0.5); border-radius: 3px; }
      .animate-fadeIn { animation: fadeIn 0.3s ease-in-out; }
      @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
    }
  </style>
</head>

<body class="bg-gray-50 font-inter text-dark min-h-screen flex flex-col">
    <!-- 顶部导航栏 -->
    <header class="bg-white shadow-md sticky top-0 z-50 transition-all duration-300">
        <div class="container mx-auto px-4 py-3 flex items-center justify-between">
            <div class="flex items-center space-x-2">
                <i class="fa fa-exchange text-primary text-2xl"></i>
                <h1 class="text-xl md:text-2xl font-bold text-primary">HTTP TOOL @inori</h1>
            </div>
            <div class="flex items-center space-x-4">
                <button id="settings-btn" class="p-2 rounded-full hover:bg-gray-100 transition-colors">
                    <i class="fa fa-cog text-gray-600"></i>
                </button>
                <button id="theme-toggle" class="p-2 rounded-full hover:bg-gray-100 transition-colors">
                    <i class="fa fa-moon-o text-gray-600"></i>
                </button>
                <button id="help-btn" class="p-2 rounded-full hover:bg-gray-100 transition-colors">
                    <i class="fa fa-question-circle text-gray-600"></i>
                </button>
            </div>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="flex-grow container mx-auto px-4 py-6">
        
        <!-- 请求配置区域 -->
        <div class="bg-white rounded-xl shadow-lg p-5 mb-6 transform transition-all duration-300 hover:shadow-xl">
            <div class="flex flex-col md:flex-row gap-4 mb-4">
                <!-- 请求方法选择 -->
                <div class="flex items-center">
                    <select id="method"
                        class="bg-light border-0 rounded-lg px-4 py-3 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all">
                        <option value="GET">GET</option>
                        <option value="POST">POST</option>
                        <option value="PUT">PUT</option>
                        <option value="DELETE">DELETE</option>
                        <option value="PATCH">PATCH</option>
                        <option value="HEAD">HEAD</option>
                        <option value="OPTIONS">OPTIONS</option>
                    </select>
                </div>

                <!-- URL输入框 -->
                <div class="flex-grow relative">
                    <div class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500">
                        <i class="fa fa-link"></i>
                    </div>
                    <input type="text" id="url" placeholder="https://api.example.com/endpoint"
                        class="w-full pl-10 pr-4 py-3 bg-light border-0 rounded-lg focus:ring-2 focus:ring-primary/50 transition-all"
                        value="https://httpbin.org/post">
                </div>

                <!-- 发送/停止按钮 -->
                <div class="flex gap-2">
                    <button id="send-btn"
                        class="bg-primary hover:bg-primary/90 text-white px-6 py-3 rounded-lg font-medium transition-all transform hover:scale-105 flex items-center gap-2">
                        <i class="fa fa-paper-plane"></i>
                        <span>发送请求</span>
                    </button>
                    <button id="stop-btn"
                        class="bg-danger hover:bg-danger/90 text-white px-6 py-3 rounded-lg font-medium transition-all transform hover:scale-105 flex items-center gap-2 hidden">
                        <i class="fa fa-stop"></i>
                        <span>停止</span>
                    </button>
                </div>
            </div>

            <!-- 请求设置信息显示 -->
            <div id="request-info" class="mb-4 text-sm text-gray-500 hidden">
                <i class="fa fa-info-circle text-primary"></i>
                <span id="request-info-text">当前设置: 单次请求</span>
            </div>

            <!-- 请求头配置 -->
            <div class="mb-4">
                <div class="flex items-center justify-between mb-2 cursor-pointer" id="headers-toggle">
                    <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                        <i class="fa fa-header text-primary"></i>
                        请求头
                    </h3>
                    <i class="fa fa-chevron-down text-gray-500 transition-transform duration-300" id="headers-icon"></i>
                </div>

                <div id="headers-container"
                    class="max-h-60 overflow-y-auto scrollbar-thin bg-gray-50 p-3 rounded-lg border border-gray-200 space-y-2">
                    <div class="header-row flex gap-2">
                        <input type="text" placeholder="Key"
                            class="header-key flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm">
                        <input type="text" placeholder="Value"
                            class="header-value flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm">
                        <button
                            class="remove-header text-gray-400 hover:text-danger p-2 rounded hover:bg-red-50 transition-colors">
                            <i class="fa fa-trash"></i>
                        </button>
                    </div>

                    <button id="add-header"
                        class="w-full py-2 text-primary border border-dashed border-primary/50 rounded-lg hover:bg-primary/5 transition-colors flex items-center justify-center gap-1 text-sm">
                        <i class="fa fa-plus"></i>
                        <span>添加请求头</span>
                    </button>
                </div>
            </div>

            <!-- 请求体（POST/PUT/PATCH时显示） -->
            <div id="body-container" class="mb-4 hidden">
                <div class="flex items-center justify-between mb-2">
                    <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                        <i class="fa fa-file-text-o text-primary"></i>
                        请求体（支持文本/JSON格式）
                    </h3>
                    <select id="body-type"
                        class="text-sm bg-light border-0 rounded px-2 py-1 focus:ring-2 focus:ring-primary/50">
                        <option value="text">文本</option>
                        <option value="json" selected>JSON（推荐）</option>
                    </select>
                </div>

                <textarea id="body" placeholder='示例：{"username":"test","password":"123456"}'
                    class="w-full h-40 p-3 bg-gray-50 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary/50 scrollbar-thin font-mono text-sm"
                    value='{"username":"test","password":"123456"}'></textarea>
            </div>
        </div>

        <!-- 报文显示区域（左右布局） -->
        <div class="flex flex-col lg:flex-row gap-6 mb-6">
            <!-- 请求报文显示 -->
            <div class="bg-white rounded-xl shadow-lg p-5 transform transition-all duration-300 hover:shadow-xl flex-1">
                <div class="flex items-center justify-between mb-3">
                    <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                        <i class="fa fa-arrow-right text-primary"></i>
                        请求报文
                    </h3>
                    <button id="copy-request"
                        class="text-gray-500 hover:text-primary p-1 rounded hover:bg-gray-100 transition-colors">
                        <i class="fa fa-copy"></i>
                        <span class="ml-1 text-sm">复制</span>
                    </button>
                </div>
                <div class="relative">
                    <pre id="request-output"
                        class="bg-gray-50 p-4 rounded-lg border border-gray-200 h-80 overflow-auto scrollbar-thin font-mono text-sm text-gray-800"></pre>
                    <div id="request-copy-alert"
                        class="absolute top-2 right-2 bg-success text-white text-xs px-2 py-1 rounded opacity-0 transition-opacity duration-300">
                        已复制
                    </div>
                </div>
            </div>

            <!-- 响应报文显示 -->
            <div class="bg-white rounded-xl shadow-lg p-5 transform transition-all duration-300 hover:shadow-xl flex-1">
                <div class="flex items-center justify-between mb-3">
                    <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                        <i class="fa fa-arrow-left text-success"></i>
                        响应报文
                    </h3>
                    <div class="flex items-center gap-2">
                        <span id="response-status"
                            class="text-sm px-2 py-1 rounded-full bg-gray-100 text-gray-600"></span>
                        <span id="response-time"
                            class="text-sm px-2 py-1 rounded-full bg-gray-100 text-gray-600 hidden"></span>
                        <span id="request-count"
                            class="text-sm px-2 py-1 rounded-full bg-gray-100 text-gray-600 hidden"></span>
                        <button id="copy-response"
                            class="text-gray-500 hover:text-primary p-1 rounded hover:bg-gray-100 transition-colors">
                            <i class="fa fa-copy"></i>
                            <span class="ml-1 text-sm">复制</span>
                        </button>
                    </div>
                </div>
                <div class="relative">
                    <pre id="response-output"
                        class="bg-gray-50 p-4 rounded-lg border border-gray-200 h-80 overflow-auto scrollbar-thin font-mono text-sm text-gray-800"></pre>
                    <div id="response-copy-alert"
                        class="absolute top-2 right-2 bg-success text-white text-xs px-2 py-1 rounded opacity-0 transition-opacity duration-300">
                        已复制
                    </div>
                </div>
            </div>
        </div>
        <!-- Server配置区域 -->
        <div class="bg-white rounded-xl shadow-lg p-5 mb-6 transform transition-all duration-300 hover:shadow-xl">
        <h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center gap-2">
            <i class="fa fa-server text-primary"></i>HTTP/HTTPS Server
        </h2>

        <!-- 选项卡导航 -->
        <div class="flex items-center gap-2 mb-4 border-b pb-2">
            <div id="server-tabs" class="flex gap-1 overflow-x-auto scrollbar-thin">
            <!-- 初始选项卡 -->
            <div class="server-tab active px-4 py-2 rounded-t-lg bg-primary text-white cursor-pointer" data-tab-id="tab-1">
                Server 1
                <button class="ml-2 text-white/80 hover:text-white" data-tab-id="tab-1" onclick="removeServerTab('tab-1')">
                <i class="fa fa-times"></i>
                </button>
            </div>
            </div>
            <button id="add-server-tab" class="px-3 py-2 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors">
            <i class="fa fa-plus"></i> 添加Server
            </button>
        </div>

        <!-- 选项卡内容容器 -->
        <div id="server-tab-contents">
            <!-- 初始选项卡内容 -->
            <div class="server-tab-content active" id="tab-1-content">
            <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
                <!-- 协议选择 -->
                <div>
                <label class="block text-sm font-medium text-gray-700 mb-1">协议</label>
                <select class="server-protocol w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="tab-1">
                    <option value="http">HTTP</option>
                    <option value="https">HTTPS</option>
                </select>
                </div>

                <!-- 端口输入 -->
                <div>
                <label class="block text-sm font-medium text-gray-700 mb-1">端口 <span class="text-danger" id="port-error-tab-1"></span></label>
                <input type="number" min="1" max="65535" value="8080" class="server-port w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="tab-1" placeholder="输入端口号（1-65535）">
                </div>
            </div>

            <!-- HTTPS证书上传（默认隐藏） -->
            <div class="server-ssl-config hidden mb-4" data-tab-id="tab-1">
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                <div>
                    <label class="block text-sm font-medium text-gray-700 mb-1">SSL 私钥文件（.key）</label>
                    <input type="file" accept=".key" class="server-ssl-key w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="tab-1">
                    <input type="hidden" class="server-ssl-key-content" data-tab-id="tab-1">
                </div>
                <div>
                    <label class="block text-sm font-medium text-gray-700 mb-1">SSL 证书文件（.cert/.pem）</label>
                    <input type="file" accept=".cert,.pem" class="server-ssl-cert w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="tab-1">
                    <input type="hidden" class="server-ssl-cert-content" data-tab-id="tab-1">
                </div>
                </div>
                <p class="text-xs text-gray-500 mt-1">HTTPS模式需上传有效的SSL证书和私钥文件</p>
            </div>

            <!-- 响应路径 -->
            <div class="mb-4">
                <label class="block text-sm font-medium text-gray-700 mb-1">响应路径（如 /api/data）</label>
                <input type="text" value="/" class="server-path w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="tab-1" placeholder="输入请求路径">
            </div>

            <!-- 响应状态码 -->
            <div class="mb-4">
                <label class="block text-sm font-medium text-gray-700 mb-1">响应状态码</label>
                <input type="number" min="100" max="599" value="200" class="server-status-code w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="tab-1" placeholder="输入状态码（100-599）">
            </div>

            <!-- 响应头配置 -->
            <div class="mb-4">
                <div class="flex items-center justify-between mb-2 cursor-pointer" onclick="toggleServerHeaders('tab-1')">
                <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                    <i class="fa fa-header text-primary"></i>
                    响应头
                </h3>
                <i class="fa fa-chevron-down text-gray-500 transition-transform duration-300" id="server-headers-icon-tab-1"></i>
                </div>

                <div id="server-headers-container-tab-1" class="max-h-60 overflow-y-auto scrollbar-thin bg-gray-50 p-3 rounded-lg border border-gray-200 space-y-2">
                <div class="server-header-row flex gap-2">
                    <input type="text" placeholder="Key（如 Content-Type）" value="Content-Type" class="server-header-key flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm" data-tab-id="tab-1">
                    <input type="text" placeholder="Value" value="application/json" class="server-header-value flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm" data-tab-id="tab-1">
                    <button class="remove-server-header text-gray-400 hover:text-danger p-2 rounded hover:bg-red-50 transition-colors" onclick="removeServerHeader(this)">
                    <i class="fa fa-trash"></i>
                    </button>
                </div>

                <button class="add-server-header w-full py-2 text-primary border border-dashed border-primary/50 rounded-lg hover:bg-primary/5 transition-colors flex items-center justify-center gap-1 text-sm" data-tab-id="tab-1" onclick="addServerHeader('tab-1')">
                    <i class="fa fa-plus"></i>
                    <span>添加响应头</span>
                </button>
                </div>
            </div>

            <!-- 响应体配置 -->
            <div class="mb-4">
                <div class="flex items-center justify-between mb-2">
                <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                    <i class="fa fa-file-text-o text-primary"></i>
                    响应体
                </h3>
                <select class="server-body-type text-sm bg-light border-0 rounded px-2 py-1 focus:ring-2 focus:ring-primary/50" data-tab-id="tab-1">
                    <option value="text">文本</option>
                    <option value="json" selected>JSON（推荐）</option>
                </select>
                </div>

                <textarea class="server-body w-full h-40 p-3 bg-gray-50 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary/50 scrollbar-thin font-mono text-sm" data-tab-id="tab-1" placeholder='示例：{"code":200,"data":"success"}'>{"code":200,"message":"success","data":{"id":1,"content":"test server response"}}</textarea>
            </div>

            <!-- 状态和控制按钮 -->
            <div class="flex items-center justify-between">
                <div class="server-status text-sm px-3 py-2 rounded-full bg-gray-100 text-gray-600" id="server-status-tab-1">
                <i class="fa fa-circle-o text-gray-500"></i> 已停止
                </div>
                <div class="flex gap-2">
                <button class="start-server bg-success hover:bg-success/90 text-white px-6 py-2 rounded-lg font-medium transition-all transform hover:scale-105 flex items-center gap-2" data-tab-id="tab-1" onclick="startServer('tab-1')">
                    <i class="fa fa-play"></i>
                    <span>启动</span>
                </button>
                <button class="stop-server bg-danger hover:bg-danger/90 text-white px-6 py-2 rounded-lg font-medium transition-all transform hover:scale-105 flex items-center gap-2 hidden" data-tab-id="tab-1" onclick="stopServer('tab-1')">
                    <i class="fa fa-stop"></i>
                    <span>停止</span>
                </button>
                </div>
            </div>
            </div>
        </div>
        </div>
        <!-- 签名工具区域 -->
        <div class="bg-white rounded-xl shadow-lg p-6 mb-6 transform transition-all duration-300 hover:shadow-xl">
            <h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center gap-2">
                <i class="fa fa-key text-primary"></i>签名工具
            </h2>

            <div class="space-y-4">
                <div>
                    <label for="signature-content" class="block text-sm font-medium text-gray-700 mb-1">待签名内容</label>
                    <textarea id="signature-content" rows="4"
                        class="w-full bg-light border-0 rounded-lg px-4 py-3 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all"
                        placeholder="请输入需要计算签名的内容..."></textarea>
                </div>

                <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div>
                        <label for="signature-algorithm"
                            class="block text-sm font-medium text-gray-700 mb-1">签名算法</label>
                        <select id="signature-algorithm"
                            class="w-full bg-light border-0 rounded-lg px-4 py-3 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all">
                            <option value="md5">MD5（兼容HTTP环境）</option>
                            <option value="sha1">SHA-1（需HTTPS/localhost）</option>
                            <option value="sha256" selected>SHA-256（推荐）</option>
                            <option value="sha512">SHA-512</option>
                        </select>
                    </div>

                    <div>
                        <label for="signature-encoding"
                            class="block text-sm font-medium text-gray-700 mb-1">编码方式</label>
                        <select id="signature-encoding"
                            class="w-full bg-light border-0 rounded-lg px-4 py-3 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all">
                            <option value="32lower">32位小写（MD5完整/SHA-256前半）</option>
                            <option value="32upper">32位大写（MD5完整/SHA-256前半）</option>
                            <option value="16lower">16位小写（MD5前半/SHA-256前16）</option>
                            <option value="16upper">16位大写（MD5前半/SHA-256前16）</option>
                            <option value="64lower">64位小写（SHA-256完整/SHA-512前半）</option>
                            <option value="64upper">64位大写（SHA-256完整/SHA-512前半）</option>
                            <option value="128lower" disabled>128位小写（SHA-512完整）</option>
                            <option value="128upper" disabled>128位大写（SHA-512完整）</option>
                            <option value="base64">BASE64（对应完整哈希）</option>
                        </select>
                    </div>
                </div>

                <div class="flex gap-3">
                    <button id="calculate-signature"
                        class="px-6 py-3 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors flex items-center gap-2">
                        <i class="fa fa-calculator"></i>计算签名
                    </button>
                    <button id="copy-signature"
                        class="px-6 py-3 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors flex items-center gap-2">
                        <i class="fa fa-copy"></i>复制结果
                    </button>
                    <button id="clear-signature"
                        class="px-6 py-3 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors flex items-center gap-2">
                        <i class="fa fa-eraser"></i>清空
                    </button>
                </div>

                <div>
                    <label for="signature-result" class="block text-sm font-medium text-gray-700 mb-1">签名结果</label>
                    <div class="relative">
                        <textarea id="signature-result" rows="4"
                            class="w-full bg-light border-0 rounded-lg px-4 py-3 font-mono text-sm text-gray-800 focus:ring-2 focus:ring-primary/50 transition-all"
                            placeholder="签名结果将显示在这里..." readonly></textarea>
                        <div id="signature-copy-alert"
                            class="absolute top-2 right-2 bg-success text-white text-xs px-2 py-1 rounded opacity-0 transition-opacity duration-300">
                            已复制
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </main>

    <!-- 帮助模态框 -->
    <div id="help-modal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center p-4">
        <div class="bg-white rounded-xl max-w-lg w-full max-h-[80vh] overflow-y-auto p-6 shadow-2xl">
            <div class="flex justify-between items-center mb-4">
                <h2 class="text-xl font-bold text-primary">使用帮助</h2>
                <button id="close-help" class="text-gray-500 hover:text-gray-700">
                    <i class="fa fa-times text-xl"></i>
                </button>
            </div>
            <div class="space-y-4 text-gray-700">
                <!-- 帮助内容保持不变 -->
                <div>
                    <h3 class="font-semibold text-lg mb-2">请求体使用说明</h3>
                    <p>1. 仅 <span class="text-primary font-medium">POST/PUT/PATCH</span> 方法支持请求体</p>
                    <p>2. 选择 "JSON" 格式时，需输入标准JSON（如：{"key":"value"}），工具会自动添加 Content-Type: application/json 头</p>
                    <p>3. 选择 "文本" 格式时，默认 Content-Type: text/plain，可手动修改请求头</p>
                </div>
                <div>
                    <h3 class="font-semibold text-lg mb-2">签名工具</h3>
                    <p>1. 输入需要计算签名的内容</p>
                    <p>2. 选择签名算法（MD5、SHA-1、SHA-256、SHA-512）</p>
                    <p>3. 选择输出编码方式（十六进制或Base64）</p>
                    <p>4. 点击"计算签名"按钮获取结果</p>
                </div>
                <div>
                    <h3 class="font-semibold text-lg mb-2">基本使用</h3>
                    <p>1. 选择请求方法（GET/POST/PUT等）</p>
                    <p>2. 输入请求URL（需包含 http:// 或 https://）</p>
                    <p>3. （可选）添加自定义请求头（如Authorization）</p>
                    <p>4. （POST/PUT/PATCH）输入请求体内容</p>
                    <p>5. 点击"发送请求"按钮，查看请求/响应报文</p>
                </div>
            </div>
        </div>
    </div>

    <!-- 设置模态框 -->
    <div id="settings-modal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center p-4">
        <div class="bg-white rounded-xl max-w-lg w-full max-h-[80vh] overflow-y-auto p-6 shadow-2xl">
            <div class="flex justify-between items-center mb-4">
                <h2 class="text-xl font-bold text-primary">请求设置</h2>
                <button id="close-settings" class="text-gray-500 hover:text-gray-700">
                    <i class="fa fa-times text-xl"></i>
                </button>
            </div>
            <div class="space-y-6 text-gray-700">
                <!-- 请求方式设置 -->
                <div>
                    <h3 class="font-semibold text-lg mb-3">请求方式</h3>
                    <div class="space-y-3">
                        <div class="flex items-center">
                            <input type="radio" id="request-type-single" name="request-type" value="single" checked
                                class="w-4 h-4 text-primary">
                            <label for="request-type-single" class="ml-2">单次请求（默认）：只请求一次</label>
                        </div>
                        <div class="flex items-center">
                            <input type="radio" id="request-type-multiple" name="request-type" value="multiple"
                                class="w-4 h-4 text-primary">
                            <label for="request-type-multiple" class="ml-2">按次请求：指定请求次数</label>
                            <input type="number" id="request-count-input" min="1" value="5"
                                class="ml-3 w-20 px-2 py-1 border border-gray-300 rounded text-sm" disabled>
                        </div>
                        <div class="flex items-center">
                            <input type="radio" id="request-type-loop" name="request-type" value="loop"
                                class="w-4 h-4 text-primary">
                            <label for="request-type-loop" class="ml-2">循环请求：不停请求，直到点击停止</label>
                        </div>
                    </div>
                    <div class="mt-3">
                        <label for="request-interval" class="block text-sm font-medium text-gray-700 mb-1">
                            请求间隔（毫秒）
                        </label>
                        <input type="number" id="request-interval" min="100" value="1000"
                            class="w-full px-3 py-2 border border-gray-300 rounded">
                        <p class="text-xs text-gray-500 mt-1">设置多次请求之间的间隔时间，最小值为100毫秒</p>
                    </div>
                </div>

                <!-- 数据保存设置 -->
                <div>
                    <h3 class="font-semibold text-lg mb-3">数据保存</h3>
                    <div class="flex items-center mb-3">
                        <input type="checkbox" id="save-request-data" class="w-4 h-4 text-primary">
                        <label for="save-request-data" class="ml-2">保存请求数据</label>
                    </div>
                    
                    <div id="export-formats" class="ml-6 space-y-2 hidden">
                        <p class="text-sm font-medium">导出格式：</p>
                        <div class="flex flex-wrap gap-3">
                            <label class="inline-flex items-center">
                                <input type="checkbox" name="export-format" value="json" checked class="w-3 h-3 text-primary">
                                <span class="ml-1 text-sm">JSON</span>
                            </label>
                            <label class="inline-flex items-center">
                                <input type="checkbox" name="export-format" value="txt" checked class="w-3 h-3 text-primary">
                                <span class="ml-1 text-sm">TXT</span>
                            </label>
                            <label class="inline-flex items-center">
                                <input type="checkbox" name="export-format" value="xlsx" checked class="w-3 h-3 text-primary">
                                <span class="ml-1 text-sm">Excel</span>
                            </label>
                            <label class="inline-flex items-center">
                                <input type="checkbox" name="export-format" value="docx" class="w-3 h-3 text-primary">
                                <span class="ml-1 text-sm">Word</span>
                            </label>
                        </div>
                    </div>
                    
                    <div class="mt-3 text-sm text-gray-500">
                        <p>将保存以下信息：</p>
                        <ul class="list-disc list-inside mt-1 space-y-1">
                            <li>请求序号和基本信息</li>
                            <li>请求时间和响应时间</li>
                            <li>等待响应时间（毫秒）</li>
                            <li>响应状态码</li>
                            <li>请求和响应报文</li>
                        </ul>
                    </div>
                </div>

                <div class="flex justify-end pt-4 border-t border-gray-200">
                    <button id="save-settings"
                        class="px-6 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors">
                        保存设置
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- 页脚 -->
    <footer class="bg-white border-t border-gray-200 py-4 mt-8">
        <div class="container mx-auto px-4 text-center text-gray-500 text-sm">
            <p>HTTP/HTTPS 测试工具 &copy; 2023</p>
        </div>
    </footer>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            // DOM元素
            const methodSelect = document.getElementById('method');
            const urlInput = document.getElementById('url');
            const sendBtn = document.getElementById('send-btn');
            const stopBtn = document.getElementById('stop-btn');
            const headersToggle = document.getElementById('headers-toggle');
            const headersContainer = document.getElementById('headers-container');
            const headersIcon = document.getElementById('headers-icon');
            const addHeaderBtn = document.getElementById('add-header');
            const bodyContainer = document.getElementById('body-container');
            const bodyInput = document.getElementById('body');
            const bodyTypeSelect = document.getElementById('body-type');
            const requestOutput = document.getElementById('request-output');
            const responseOutput = document.getElementById('response-output');
            const responseStatus = document.getElementById('response-status');
            const responseTime = document.getElementById('response-time');
            const requestCount = document.getElementById('request-count');
            const copyRequestBtn = document.getElementById('copy-request');
            const copyResponseBtn = document.getElementById('copy-response');
            const requestCopyAlert = document.getElementById('request-copy-alert');
            const responseCopyAlert = document.getElementById('response-copy-alert');
            const helpBtn = document.getElementById('help-btn');
            const helpModal = document.getElementById('help-modal');
            const closeHelpBtn = document.getElementById('close-help');
            const themeToggle = document.getElementById('theme-toggle');
            const requestInfo = document.getElementById('request-info');
            const requestInfoText = document.getElementById('request-info-text');

            // 设置相关元素
            const settingsBtn = document.getElementById('settings-btn');
            const settingsModal = document.getElementById('settings-modal');
            const closeSettingsBtn = document.getElementById('close-settings');
            const saveSettingsBtn = document.getElementById('save-settings');
            const requestTypeRadios = document.querySelectorAll('input[name="request-type"]');
            const requestCountInput = document.getElementById('request-count-input');
            const requestIntervalInput = document.getElementById('request-interval');
            const saveRequestDataCheckbox = document.getElementById('save-request-data');

            // 签名工具相关元素
            const signatureContent = document.getElementById('signature-content');
            const signatureAlgorithm = document.getElementById('signature-algorithm');
            const signatureEncoding = document.getElementById('signature-encoding');
            const signatureResult = document.getElementById('signature-result');
            const calculateSignatureBtn = document.getElementById('calculate-signature');
            const copySignatureBtn = document.getElementById('copy-signature');
            const clearSignatureBtn = document.getElementById('clear-signature');
            const signatureCopyAlert = document.getElementById('signature-copy-alert');

            // 请求配置变量
            let requestSettings = {
                type: 'single', // single, multiple, loop
                count: 5,
                interval: 1000,
                saveData: false
            };
            
            // 请求控制变量
            let requestLoop = null;
            let currentRequestCount = 0;
            let totalRequestCount = 0;
            let requestHistory = [];

            // 请求体显示逻辑
            const BODY_METHODS = ['POST', 'PUT', 'PATCH'];
            
            const toggleBodyContainer = () => {
                const needsBody = BODY_METHODS.includes(methodSelect.value);
                if (needsBody) {
                    bodyContainer.classList.remove('hidden');
                    bodyContainer.classList.add('block', 'animate-fadeIn');
                } else {
                    bodyContainer.classList.add('hidden');
                    bodyContainer.classList.remove('block', 'animate-fadeIn');
                }
            };
            toggleBodyContainer();
            methodSelect.addEventListener('change', toggleBodyContainer);

            // 请求头显示/隐藏
            let headersVisible = true;
            headersToggle.addEventListener('click', () => {
                headersVisible = !headersVisible;
                headersContainer.style.maxHeight = headersVisible ? '240px' : '0px';
                headersIcon.style.transform = headersVisible ? 'rotate(0deg)' : 'rotate(-180deg)';
            });

            // 添加请求头
            addHeaderBtn.addEventListener('click', () => {
                const headerRow = document.createElement('div');
                headerRow.className = 'header-row flex gap-2 animate-fadeIn';
                headerRow.innerHTML = `
                    <input type="text" placeholder="Key" class="header-key flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm">
                    <input type="text" placeholder="Value" class="header-value flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm">
                    <button class="remove-header text-gray-400 hover:text-danger p-2 rounded hover:bg-red-50 transition-colors">
                        <i class="fa fa-trash"></i>
                    </button>
                `;
                headersContainer.insertBefore(headerRow, addHeaderBtn);
                headerRow.querySelector('.remove-header').addEventListener('click', () => {
                    headerRow.classList.add('opacity-0');
                    setTimeout(() => headerRow.remove(), 300);
                });
            });

            // 初始删除按钮事件绑定
            document.querySelectorAll('.remove-header').forEach(btn => {
                btn.addEventListener('click', () => {
                    const row = btn.closest('.header-row');
                    row.classList.add('opacity-0');
                    setTimeout(() => row.remove(), 300);
                });
            });

            // 请求方式单选按钮事件
            requestTypeRadios.forEach(radio => {
                radio.addEventListener('change', () => {
                    requestCountInput.disabled = radio.value !== 'multiple';
                });
            });
        
            async function sendRequest() {
                if (sendBtn.disabled) return; // 避免重复触发请求
                sendBtn.disabled = true; // 锁定按钮
                // 清除之前的输出
                requestOutput.textContent = '';
                responseOutput.textContent = '';
                responseStatus.textContent = '';
                responseTime.textContent = '';
                responseTime.classList.add('hidden');
                
                // 重置请求计数（仅在sendRequest中管理，避免重复递增）
                currentRequestCount = 0; 
                totalRequestCount = requestSettings.type === 'multiple' ? requestSettings.count : 1;
                requestHistory = [];
                
                // 显示停止按钮，隐藏发送按钮
                sendBtn.classList.add('hidden');
                stopBtn.classList.remove('hidden');
                
                // 根据请求类型处理
                if (requestSettings.type === 'loop') {
                    // 循环请求（保留原逻辑，仅修复计数）
                    requestLoop = setInterval(() => {
                        currentRequestCount++; // 仅在这里递增
                        executeSingleRequest(currentRequestCount, Infinity);
                    }, requestSettings.interval);
                    currentRequestCount++;
                    executeSingleRequest(currentRequestCount, Infinity);
                } else if (requestSettings.type === 'multiple') {
                    // 多次请求（核心修复：用for循环i作为请求序号，确保连续）
                    requestLoop = null;
                    for (let i = 1; i <= requestSettings.count; i++) {
                        if (requestLoop === 'stopped') break; // 停止标志
                        
                        // 传入循环变量i作为请求序号（确保1、2、3、4、5连续）
                        await executeSingleRequest(i, requestSettings.count);
                        currentRequestCount = i; // 同步计数，与循环保持一致
                        
                        // 非最后一次请求，等待间隔（确保前一次完成后再下一次）
                        if (i < requestSettings.count) {
                            await new Promise(resolve => {
                                const timer = setTimeout(() => {
                                    if (requestLoop !== 'stopped') resolve();
                                }, requestSettings.interval);
                                // 若中途停止，清除定时器
                                if (requestLoop === 'stopped') clearTimeout(timer);
                            });
                        }
                    }
                    // 所有请求完成后导出
                    if (requestSettings.saveData && requestLoop !== 'stopped') {
                        exportRequestData(requestHistory);
                    }
                    // 恢复按钮
                    stopBtn.classList.add('hidden');
                    sendBtn.classList.remove('hidden');
                } else {
                    // 单次请求（用1作为固定序号）
                    await executeSingleRequest(1, 1);
                    if (requestSettings.saveData) {
                        exportRequestData(requestHistory);
                    }
                    stopBtn.classList.add('hidden');
                    sendBtn.classList.remove('hidden');
                }
                sendBtn.disabled = false;
            }
            async function executeSingleRequest(requestNumber, total) {
                const method = methodSelect.value;
                const url = urlInput.value.trim();
                
                // 基础验证（保留原逻辑）
                if (!url) {
                    alert('请输入请求URL');
                    stopBtn.click();
                    return;
                }
                try {
                    new URL(url);
                } catch (e) {
                    alert('URL格式不正确（需包含 http:// 或 https://）');
                    stopBtn.click();
                    return;
                }
                
                // 收集请求头和请求体（保留原逻辑）
                const headers = {};
                document.querySelectorAll('.header-row').forEach(row => {
                    const key = row.querySelector('.header-key').value.trim();
                    const value = row.querySelector('.header-value').value.trim();
                    if (key) headers[key] = value;
                });
                let body = null;
                if (BODY_METHODS.includes(method)) {
                    body = bodyInput.value.trim();
                    if (!body) {
                        alert(`【${method}】方法需输入请求体内容`);
                        stopBtn.click();
                        return;
                    }
                    if (bodyTypeSelect.value === 'json') {
                        try {
                            JSON.parse(body);
                            if (!headers['Content-Type']) headers['Content-Type'] = 'application/json';
                        } catch (e) {
                            alert('JSON格式不正确（示例：{"key":"value"}）');
                            stopBtn.click();
                            return;
                        }
                    } else if (!headers['Content-Type']) {
                        headers['Content-Type'] = 'text/plain';
                    }
                }
                
                // 构建请求报文预览（保留原逻辑）
                let requestPreview = `${method} ${new URL(url).pathname + new URL(url).search} HTTP/1.1\n`;
                requestPreview += `Host: ${new URL(url).host}\n`;
                Object.entries(headers).forEach(([key, value]) => {
                    requestPreview += `${key}: ${value}\n`;
                });
                requestPreview += '\n';
                if (body) requestPreview += body;
                requestOutput.textContent = requestPreview;
                
                // 初始化请求数据（用传入的requestNumber作为序号，确保1、2、3...连续）
                const requestData = {
                    requestNumber: requestNumber, // 关键修复：序号由外部传入
                    url: url,
                    method: method,
                    requestTime: new Date().toISOString(),
                    requestHeaders: headers,
                    requestBody: body,
                    requestText: requestPreview,
                    responseTime: null,
                    waitTime: null,
                    status: null,
                    statusText: null,
                    responseText: null
                };
                
                //  UI状态更新（保留原逻辑）
                responseOutput.textContent = '';
                responseStatus.textContent = `请求中（${requestNumber}/${total === Infinity ? '∞' : total}）`;
                responseStatus.className = 'text-sm px-2 py-1 rounded-full bg-warning/20 text-warning';
                responseTime.classList.add('hidden');
                requestCount.textContent = `${requestNumber}/${total === Infinity ? '∞' : total}`;
                requestCount.classList.remove('hidden');
                
                // 发送请求（保留原逻辑，仅修复历史记录）
                const startTime = performance.now();
                try {
                    sendBtn.disabled = true;
                    sendBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i><span>请求中...</span>';
                    
                    const response = await fetch(url, {
                        method,
                        headers,
                        body: body || undefined,
                        mode: 'cors',
                        cache: 'no-cache'
                    });
                    
                    // 处理响应（保留原逻辑）
                    const endTime = performance.now();
                    const duration = endTime - startTime;
                    responseStatus.textContent = `${response.status} ${response.statusText}`;
                    responseStatus.className = response.ok 
                        ? 'text-sm px-2 py-1 rounded-full bg-success/20 text-success' 
                        : 'text-sm px-2 py-1 rounded-full bg-danger/20 text-danger';
                    responseTime.textContent = `${duration.toFixed(2)} ms`;
                    responseTime.className = 'text-sm px-2 py-1 rounded-full bg-primary/20 text-primary';
                    responseTime.classList.remove('hidden');
                    
                    // 构建响应报文（保留原逻辑）
                    let responseText = `HTTP/1.1 ${response.status} ${response.statusText}\n`;
                    response.headers.forEach((value, key) => {
                        responseText += `${key}: ${value}\n`;
                    });
                    responseText += '\n';
                    let responseBody = await response.text();
                    if (response.headers.get('content-type')?.includes('application/json') && responseBody) {
                        try {
                            responseBody = JSON.stringify(JSON.parse(responseBody), null, 2);
                        } catch (e) {}
                    }
                    responseText += responseBody;
                    responseOutput.textContent = responseText;
                    
                    // 更新请求数据（序号已固定，无需修改）
                    requestData.responseTime = new Date().toISOString();
                    requestData.waitTime = duration;
                    requestData.status = response.status;
                    requestData.statusText = response.statusText;
                    requestData.responseText = responseText;
                    
                    // 保存历史（确保每次请求都被记录）
                    if (requestSettings.saveData) {
                        requestHistory.push(requestData);
                    }
                } catch (error) {
                    // 错误场景也记录（避免漏记失败的请求）
                    responseOutput.textContent = `请求失败: ${error.message}\n（跨域问题可尝试添加 Access-Control-Allow-Origin 头）`;
                    responseStatus.textContent = '请求失败';
                    responseStatus.className = 'text-sm px-2 py-1 rounded-full bg-danger/20 text-danger';
                    
                    requestData.responseTime = new Date().toISOString();
                    requestData.waitTime = performance.now() - startTime;
                    requestData.status = 'ERROR';
                    requestData.statusText = error.message;
                    requestData.responseText = responseOutput.textContent;
                    
                    if (requestSettings.saveData) {
                        requestHistory.push(requestData);
                    }
                } finally {
                    sendBtn.disabled = false;
                    sendBtn.innerHTML = '<i class="fa fa-paper-plane"></i><span>发送请求</span>';
                }
            }
            // 保存设置
            saveSettingsBtn.addEventListener('click', () => {
                // 获取选中的请求类型
                let selectedType = 'single';
                requestTypeRadios.forEach(radio => {
                    if (radio.checked) {
                        selectedType = radio.value;
                    }
                });

                // 验证输入
                const count = parseInt(requestCountInput.value) || 1;
                const interval = parseInt(requestIntervalInput.value) || 1000;
                const exportFormats = [];
                document.querySelectorAll('input[name="export-format"]:checked').forEach(checkbox => {
                    exportFormats.push(checkbox.value);
                });
                // 更新设置
                requestSettings = {
                    type: selectedType,
                    count: Math.max(1, count),
                    interval: Math.max(100, interval),
                    saveData: saveRequestDataCheckbox.checked,
                    exportFormats: exportFormats  // 添加导出格式设置
                };

                // 更新显示
                updateRequestInfo();

                // 关闭模态框
                settingsModal.classList.add('hidden');
                settingsModal.classList.remove('flex');
                document.body.style.overflow = '';
            });
            // 添加多种格式导出功能
            function exportRequestData(history) {
                const formats = requestSettings.exportFormats || ['json', 'txt', 'xlsx'];
                if (history.length === 0) {
                    alert('无请求记录可导出');
                    return;
                }
                alert(`开始导出${formats.length}个文件，请稍候...`);
                formats.forEach(format => {
                    const timestamp = new Date().getTime();
                    switch(format) {
                        case 'json':
                            // 原有JSON导出逻辑（无需修改）
                            const jsonData = JSON.stringify(history, null, 2);
                            downloadFile(
                                `data:text/json;charset=utf-8,${encodeURIComponent(jsonData)}`,
                                `request-history-${timestamp}.json`
                            );
                            break;
                        case 'txt':
                            exportAsTXT(history);
                            break;
                        case 'xlsx':
                            // 修复点：添加Excel导出函数调用（复用已实现的exportAsXLSX）
                            exportAsXLSX(history);
                            break;
                        case 'docx':
                            // 修复点：添加Word导出函数调用（复用已实现的exportAsDOCX）
                            exportAsDOCX(history);
                            break;
                    }
                });
                alert('所有文件导出完成！');
            }

            function downloadFile(dataUrl, fileName) {
                const downloadAnchorNode = document.createElement('a');
                downloadAnchorNode.setAttribute("href", dataUrl);
                downloadAnchorNode.setAttribute("download", fileName);
                document.body.appendChild(downloadAnchorNode);
                downloadAnchorNode.click();
                downloadAnchorNode.remove();
            }
            // JSON导出
            function exportAsJSON(history) {
                const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(history, null, 2));
                const downloadAnchorNode = document.createElement('a');
                downloadAnchorNode.setAttribute("href", dataStr);
                downloadAnchorNode.setAttribute("download", `request-history-${new Date().getTime()}.json`);
                document.body.appendChild(downloadAnchorNode);
                downloadAnchorNode.click();
                downloadAnchorNode.remove();
            }


            // TXT导出
            function exportAsTXT(history) {
                let textContent = `请求历史记录 - ${new Date().toLocaleString()}\n\n`;
                
                history.forEach(item => {
                    textContent += `===== 第 ${item.requestNumber} 次请求 =====\n`;
                    textContent += `时间: ${new Date(item.requestTime).toLocaleString()}\n`;
                    textContent += `方法: ${item.method} ${item.url}\n`;
                    textContent += `状态: ${item.status} ${item.statusText}\n`;
                    textContent += `响应时间: ${item.waitTime}ms\n\n`;
                    // 修复点1：添加请求报文（保留原格式，用===分隔避免混淆）
                    textContent += `请求报文:\n${item.requestText || '无请求报文'}\n\n`;
                    // 修复点2：添加响应报文（保留原格式，用===分隔避免混淆）
                    textContent += `响应报文:\n${item.responseText || '无响应报文'}\n\n`;
                    textContent += "========================================\n\n"; // 分隔符，提升可读性
                });
                
                const dataStr = "data:text/plain;charset=utf-8," + encodeURIComponent(textContent);
                const downloadAnchorNode = document.createElement('a');
                downloadAnchorNode.setAttribute("href", dataStr);
                downloadAnchorNode.setAttribute("download", `request-history-${new Date().getTime()}.txt`);
                document.body.appendChild(downloadAnchorNode);
                downloadAnchorNode.click();
                downloadAnchorNode.remove();
            }

            // Excel导出
            function exportAsXLSX(history) {
                // 转换数据为适合Excel的格式
                const excelData = history.map(item => ({
                    "请求序号": item.requestNumber,
                    "请求时间": new Date(item.requestTime).toLocaleString(),
                    "方法": item.method,
                    "URL": item.url,
                    "状态码": item.status,
                    "状态描述": item.statusText,
                    "响应时间(ms)": item.waitTime,
                    "请求报文": item.requestText ,
                    "响应报文": item.responseText
                }));
                
                const worksheet = XLSX.utils.json_to_sheet(excelData);
                const workbook = XLSX.utils.book_new();
                XLSX.utils.book_append_sheet(workbook, worksheet, "请求记录");
                
                // 导出文件
                XLSX.writeFile(workbook, `request-history-${new Date().getTime()}.xlsx`);
            }

            // Word导出 (简化版)
            function exportAsDOCX(history) {
                // 注意：完整的DOCX导出需要复杂的XML处理
                // 这里使用简化的HTML转换方式
                let htmlContent = `
                <html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'>
                <head><meta charset='utf-8'><title>请求历史记录</title></head>
                <body>
                    <h1>请求历史记录 - ${new Date().toLocaleString()}</h1>
                `;
                
                history.forEach(item => {
                    htmlContent += `
                    <h2>第 ${item.requestNumber} 次请求</h2>
                    <p><strong>时间:</strong> ${new Date(item.requestTime).toLocaleString()}</p>
                    <p><strong>方法:</strong> ${item.method} ${item.url}</p>
                    <p><strong>状态:</strong> ${item.status} ${item.statusText}</p>
                    <p><strong>响应时间:</strong> ${item.waitTime}ms</p>
                    
                    <p><strong>请求报文:</strong></p>
                    <pre style="background:#f5f5f5;padding:10px;">${item.requestText}</pre>
                    
                    <p><strong>响应报文:</strong></p>
                    <pre style="background:#f5f5f5;padding:10px;">${item.responseText}</pre>
                    
                    <hr>
                    `;
                });
                
                htmlContent += `</body></html>`;
                
                const dataStr = "data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8," + encodeURIComponent(htmlContent);
                const downloadAnchorNode = document.createElement('a');
                downloadAnchorNode.setAttribute("href", dataStr);
                downloadAnchorNode.setAttribute("download", `request-history-${new Date().getTime()}.docx`);
                document.body.appendChild(downloadAnchorNode);
                downloadAnchorNode.click();
                downloadAnchorNode.remove();
            }
            // 更新请求设置信息显示
            function updateRequestInfo() {
                let infoText = '';
                switch (requestSettings.type) {
                    case 'single':
                        infoText = '当前设置: 单次请求';
                        break;
                    case 'multiple':
                        infoText = `当前设置: 按次请求 (${requestSettings.count} 次)，间隔 ${requestSettings.interval}ms`;
                        break;
                    case 'loop':
                        infoText = `当前设置: 循环请求，间隔 ${requestSettings.interval}ms`;
                        break;
                }
                requestInfoText.textContent = infoText;
                requestInfo.classList.remove('hidden');
            }

            // 发送请求
            sendBtn.addEventListener('click', () => {
                // 重置请求计数
                currentRequestCount = 0;
                totalRequestCount = requestSettings.type === 'multiple' ? requestSettings.count : 0;
                
                // 更新UI状态
                sendBtn.classList.add('hidden');
                stopBtn.classList.remove('hidden');
                requestCount.textContent = '0/0';
                requestCount.classList.remove('hidden');
                
                // 清空历史数据
                if (requestSettings.saveData) {
                    requestHistory = [];
                }

                // 执行请求
                sendRequest(); // 正确：仅保留sendRequest，它会处理multiple模式的5次请求
            });

            // 停止请求
            stopBtn.addEventListener('click', () => {
                if (requestLoop) {
                    clearInterval(requestLoop); // 循环请求用clearInterval
                    clearTimeout(requestLoop); // 多次请求用clearTimeout
                    requestLoop = 'stopped'; // 标记为停止状态
                }
                
                // 恢复UI状态
                sendBtn.classList.remove('hidden');
                stopBtn.classList.add('hidden');
                
                if (requestSettings.saveData && requestHistory.length > 0) {
                    // 提示用户即将导出，并调用导出函数
                    if (confirm(`已停止循环请求，共产生 ${requestHistory.length} 条记录，是否立即导出？`)) {
                        exportRequestData(requestHistory);
                        // （可选）导出后清空历史记录，避免重复导出
                        // requestHistory = [];
                    }
                }
            });
            // 初始化时添加导出格式选项的显示控制
            document.getElementById('save-request-data').addEventListener('change', function() {
                const exportFormats = document.getElementById('export-formats');
                if (this.checked) {
                    exportFormats.classList.remove('hidden');
                } else {
                    exportFormats.classList.add('hidden');
                }
            });
            // 执行请求
            async function executeRequest() {
                // 增加请求计数
                //currentRequestCount++;
                requestCount.textContent = `${currentRequestCount}/${totalRequestCount || '∞'}`;
                const method = methodSelect.value;
                const url = urlInput.value.trim();

                // 验证URL
                if (!url) {
                    alert('请输入请求URL');
                    stopBtn.click();
                    return;
                }

                try {
                    new URL(url);
                } catch (e) {
                    alert('URL格式不正确（需包含 http:// 或 https://）');
                    stopBtn.click();
                    return;
                }

                // 收集请求头
                const headers = {};
                document.querySelectorAll('.header-row').forEach(row => {
                    const key = row.querySelector('.header-key').value.trim();
                    const value = row.querySelector('.header-value').value.trim();
                    if (key) headers[key] = value;
                });

                // 处理请求体
                let body = null;
                if (BODY_METHODS.includes(method)) {
                    body = bodyInput.value.trim();
                    if (!body) {
                        alert(`【${method}】方法需输入请求体内容`);
                        stopBtn.click();
                        return;
                    }
                    if (bodyTypeSelect.value === 'json') {
                        try {
                            JSON.parse(body);
                            if (!headers['Content-Type']) {
                                headers['Content-Type'] = 'application/json';
                            }
                        } catch (e) {
                            alert('JSON格式不正确（示例：{"key":"value"}）');
                            stopBtn.click();
                            return;
                        }
                    } else if (!headers['Content-Type']) {
                        headers['Content-Type'] = 'text/plain';
                    }
                }

                // 构建请求报文预览
                let requestPreview = `${method} ${new URL(url).pathname + new URL(url).search} HTTP/1.1\n`;
                requestPreview += `Host: ${new URL(url).host}\n`;
                Object.entries(headers).forEach(([key, value]) => {
                    requestPreview += `${key}: ${value}\n`;
                });
                requestPreview += '\n';
                if (body) requestPreview += body;
                requestOutput.textContent = requestPreview;

                // 准备保存的请求数据（添加请求序号）
                const requestData = {
                    requestNumber: currentRequestCount,  // 添加请求序号
                    url: url,
                    method: method,
                    requestTime: new Date().toISOString(),
                    requestHeaders: headers,
                    requestBody: body,
                    requestText: requestPreview,
                    responseTime: null,
                    waitTime: null,
                    status: null,
                    statusText: null,
                    responseText: null
                };
                // 清空之前的响应
                responseOutput.textContent = '';
                responseStatus.textContent = '请求中...';
                responseStatus.className = 'text-sm px-2 py-1 rounded-full bg-warning/20 text-warning';
                responseTime.classList.add('hidden');
                
                // 更新计数
                currentRequestCount++;
                requestCount.textContent = totalRequestCount 
                    ? `${currentRequestCount}/${totalRequestCount}` 
                    : `${currentRequestCount}`;

                // 发送请求
                const startTime = performance.now();
                try {
                    sendBtn.disabled = true;
                    sendBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i><span>请求中...</span>';

                    const response = await fetch(url, {
                        method,
                        headers,
                        body: body || undefined,
                        mode: 'cors',
                        cache: 'no-cache'
                    });

                    // 处理响应
                    const endTime = performance.now();
                    const duration = endTime - startTime;
                    const waitTime = endTime - startTime;

                    responseStatus.textContent = `${response.status} ${response.statusText}`;
                    responseStatus.className = response.ok 
                        ? 'text-sm px-2 py-1 rounded-full bg-success/20 text-success' 
                        : 'text-sm px-2 py-1 rounded-full bg-danger/20 text-danger';

                    responseTime.textContent = `${duration.toFixed(2)} ms`;
                    responseTime.className = 'text-sm px-2 py-1 rounded-full bg-primary/20 text-primary';
                    responseTime.classList.remove('hidden');

                    // 构建响应报文
                    let responseText = `HTTP/1.1 ${response.status} ${response.statusText}\n`;
                    response.headers.forEach((value, key) => {
                        responseText += `${key}: ${value}\n`;
                    });
                    responseText += '\n';

                    let responseBody = await response.text();
                    if (response.headers.get('content-type')?.includes('application/json') && responseBody) {
                        try {
                            responseBody = JSON.stringify(JSON.parse(responseBody), null, 2);
                        } catch (e) {
                            // 保持原始文本
                        }
                    }
                    responseText += responseBody;
                    responseOutput.textContent = responseText;

                    // 更新请求数据
                    requestData.responseTime = new Date().toISOString();
                    requestData.waitTime = waitTime;
                    requestData.status = response.status;
                    requestData.statusText = response.statusText;
                    requestData.responseText = responseText;

                    // 保存数据
                    if (requestSettings.saveData) {
                        requestHistory.push(requestData);
                    }
                    if (requestSettings.type === 'loop' || 
                        (requestSettings.type === 'multiple' && currentRequestCount < totalRequestCount)) {
                        requestLoop = setTimeout(executeRequest, requestSettings.interval);
                    } else {
                        // 请求结束，自动保存
                        stopBtn.click();
                    }
                } catch (error) {
                    responseOutput.textContent = `请求失败: ${error.message}\n（跨域问题可尝试添加 Access-Control-Allow-Origin 头）`;
                    responseStatus.textContent = '请求失败';
                    responseStatus.className = 'text-sm px-2 py-1 rounded-full bg-danger/20 text-danger';
                    
                    // 更新请求数据
                    requestData.responseTime = new Date().toISOString();
                    requestData.waitTime = (performance.now() - startTime).toFixed(2);
                    requestData.status = 'ERROR';
                    requestData.statusText = error.message;
                    requestData.responseText = responseOutput.textContent;

                    // 保存数据
                    if (requestSettings.saveData) {
                        requestHistory.push(requestData);
                    }
                } finally {
                    sendBtn.disabled = false;
                    sendBtn.innerHTML = '<i class="fa fa-paper-plane"></i><span>发送请求</span>';

                    // 处理后续请求
                    handleNextRequest();
                }
            }

            // 处理后续请求
            function handleNextRequest() {
                // 检查是否需要继续请求
                if (requestSettings.type === 'single') {
                    // 单次请求完成
                    stopBtn.click();
                } else if (requestSettings.type === 'multiple' && currentRequestCount >= totalRequestCount) {
                    // 按次请求完成
                    stopBtn.click();
                } else if (requestSettings.type === 'loop') {
                    // 循环请求
                    requestLoop = setTimeout(executeRequest, requestSettings.interval);
                } else if (requestSettings.type === 'multiple') {
                    // 继续按次请求
                    requestLoop = setTimeout(executeRequest, requestSettings.interval);
                }
            }

            // 导出到Excel
            function exportToExcel(data) {
                // 准备导出数据
                const exportData = data.map(item => ({
                    '请求URL': item.url,
                    '请求方法': item.method,
                    '请求时间': new Date(item.requestTime).toLocaleString(),
                    '响应时间': item.responseTime ? new Date(item.responseTime).toLocaleString() : '',
                    '等待响应时间(ms)': item.waitTime,
                    '响应状态': item.status ? `${item.status} ${item.statusText}` : item.statusText,
                    '请求报文': item.requestText.substring(0, 1000), // 限制长度
                    '响应报文': item.responseText ? item.responseText.substring(0, 1000) : '' // 限制长度
                }));

                // 创建工作簿和工作表
                const ws = XLSX.utils.json_to_sheet(exportData);
                const wb = XLSX.utils.book_new();
                XLSX.utils.book_append_sheet(wb, ws, "请求记录");

                // 生成文件名
                const fileName = `http_requests_${new Date().getTime()}.xlsx`;

                // 导出文件
                XLSX.writeFile(wb, fileName);
            }

            // 复制功能
            copyRequestBtn.addEventListener('click', () => {
                navigator.clipboard.writeText(requestOutput.textContent)
                    .then(() => {
                        requestCopyAlert.style.opacity = '1';
                        setTimeout(() => requestCopyAlert.style.opacity = '0', 2000);
                    })
                    .catch(() => alert('复制失败，请手动复制'));
            });

            copyResponseBtn.addEventListener('click', () => {
                navigator.clipboard.writeText(responseOutput.textContent)
                    .then(() => {
                        responseCopyAlert.style.opacity = '1';
                        setTimeout(() => responseCopyAlert.style.opacity = '0', 2000);
                    })
                    .catch(() => alert('复制失败，请手动复制'));
            });

            // 帮助模态框
            helpBtn.addEventListener('click', () => {
                helpModal.classList.remove('hidden');
                helpModal.classList.add('flex');
                document.body.style.overflow = 'hidden';
            });
            closeHelpBtn.addEventListener('click', () => {
                helpModal.classList.add('hidden');
                helpModal.classList.remove('flex');
                document.body.style.overflow = '';
            });
            helpModal.addEventListener('click', (e) => {
                if (e.target === helpModal) closeHelpBtn.click();
            });

            // 设置模态框
            settingsBtn.addEventListener('click', () => {
                // 填充当前设置
                requestTypeRadios.forEach(radio => {
                    radio.checked = radio.value === requestSettings.type;
                });
                requestCountInput.value = requestSettings.count;
                requestIntervalInput.value = requestSettings.interval;
                saveRequestDataCheckbox.checked = requestSettings.saveData;
                requestCountInput.disabled = requestSettings.type !== 'multiple';

                // 显示模态框
                settingsModal.classList.remove('hidden');
                settingsModal.classList.add('flex');
                document.body.style.overflow = 'hidden';
            });
            closeSettingsBtn.addEventListener('click', () => {
                settingsModal.classList.add('hidden');
                settingsModal.classList.remove('flex');
                document.body.style.overflow = '';
            });
            settingsModal.addEventListener('click', (e) => {
                if (e.target === settingsModal) closeSettingsBtn.click();
            });

            // 主题切换
            let isDarkMode = false;
            themeToggle.addEventListener('click', () => {
                isDarkMode = !isDarkMode;
                const icon = themeToggle.querySelector('i');
                if (isDarkMode) {
                    document.body.classList.add('bg-gray-900', 'text-white');
                    document.body.classList.remove('bg-gray-50', 'text-dark');
                    icon.classList.replace('fa-moon-o', 'fa-sun-o');
                    icon.classList.replace('text-gray-600', 'text-yellow-400');
                } else {
                    document.body.classList.remove('bg-gray-900', 'text-white');
                    document.body.classList.add('bg-gray-50', 'text-dark');
                    icon.classList.replace('fa-sun-o', 'fa-moon-o');
                    icon.classList.replace('text-yellow-400', 'text-gray-600');
                }
            });

            // 初始化示例请求头
            const addExampleHeaders = () => {
                const headerRow = document.createElement('div');
                headerRow.className = 'header-row flex gap-2';
                headerRow.innerHTML = `
                    <input type="text" value="Accept" class="header-key flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm">
                    <input type="text" value="application/json" class="header-value flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm">
                    <button class="remove-header text-gray-400 hover:text-danger p-2 rounded hover:bg-red-50 transition-colors">
                        <i class="fa fa-trash"></i>
                    </button>
                `;
                headersContainer.insertBefore(headerRow, addHeaderBtn);
                headerRow.querySelector('.remove-header').addEventListener('click', () => headerRow.remove());
            };
            addExampleHeaders();

            // 初始化请求体示例
            bodyInput.value = '{"username":"test_user","password":"123456","timestamp":1699999999}';
        
            // 签名计算功能实现
            calculateSignatureBtn.addEventListener('click', () => {
                const content = signatureContent.value.trim();
                if (!content) {
                    alert('请输入待签名内容');
                    return;
                }

                const algorithm = signatureAlgorithm.value;
                const encoding = signatureEncoding.value;
                
                try {
                    let result;
                    
                    // 计算哈希
                    if (algorithm === 'md5') {
                        // 使用引入的blueimp-md5库
                        result = md5(content);
                    } else {
                        // 对于SHA系列算法，需要使用Web Crypto API
                        if (!window.crypto || !window.crypto.subtle) {
                            throw new Error('您的浏览器不支持加密API，请使用现代浏览器');
                        }
                        
                        // 将内容转换为Uint8Array
                        const encoder = new TextEncoder();
                        const data = encoder.encode(content);
                        
                        // 计算哈希
                        window.crypto.subtle.digest(
                            algorithm === 'sha1' ? 'SHA-1' : 
                            algorithm === 'sha256' ? 'SHA-256' : 
                            algorithm === 'sha512' ? 'SHA-512' : algorithm.toUpperCase(), 
                            data
                        )
                        .then(hashBuffer => {
                            processHashResult(hashBuffer, encoding, algorithm);
                        })
                        .catch(error => {
                            alert(`计算签名失败: ${error.message}`);
                        });
                        return; // 异步处理，提前返回
                    }
                    
                    // 处理MD5结果
                    processHashResultForMD5(result, encoding);
                    
                } catch (error) {
                    alert(`计算签名失败: ${error.message}`);
                }
            });

            // 处理MD5哈希结果
            function processHashResultForMD5(hexStr, encoding) {
                let result;
                switch(encoding) {
                    case '32lower':
                        result = hexStr;
                        break;
                    case '32upper':
                        result = hexStr.toUpperCase();
                        break;
                    case '16lower':
                        result = hexStr.substr(8, 16);
                        break;
                    case '16upper':
                        result = hexStr.substr(8, 16).toUpperCase();
                        break;
                    case 'base64':
                        // 将十六进制转换为Base64
                        const binary = hexStr.match(/.{2}/g).map(byte => String.fromCharCode(parseInt(byte, 16))).join('');
                        result = btoa(binary);
                        break;
                    default:
                        result = hexStr;
                }
                signatureResult.value = result;
            }

            // 处理Web Crypto API返回的哈希结果
            function processHashResult(hashBuffer, encoding, algorithm) {
                // 转换为十六进制
                const hexArray = Array.from(new Uint8Array(hashBuffer)).map(b => 
                    b.toString(16).padStart(2, '0')
                );
                const hexStr = hexArray.join('');
                
                // 转换为Base64
                const base64Str = btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
                
                let result;
                switch(encoding) {
                    case '32lower':
                        result = hexStr.substring(0, 32);
                        break;
                    case '32upper':
                        result = hexStr.substring(0, 32).toUpperCase();
                        break;
                    case '16lower':
                        result = hexStr.substring(0, 16);
                        break;
                    case '16upper':
                        result = hexStr.substring(0, 16).toUpperCase();
                        break;
                    case '64lower':
                        result = hexStr.substring(0, 64);
                        break;
                    case '64upper':
                        result = hexStr.substring(0, 64).toUpperCase();
                        break;
                    case 'base64':
                        result = base64Str;
                        break;
                    default:
                        result = hexStr;
                }
                
                signatureResult.value = result;
            }

            // 复制签名结果
            copySignatureBtn.addEventListener('click', () => {
                if (!signatureResult.value) {
                    alert('没有可复制的签名结果');
                    return;
                }
                
                navigator.clipboard.writeText(signatureResult.value)
                    .then(() => {
                        signatureCopyAlert.style.opacity = '1';
                        setTimeout(() => signatureCopyAlert.style.opacity = '0', 2000);
                    })
                    .catch(() => alert('复制失败，请手动复制'));
            });

            // 清空签名内容
            clearSignatureBtn.addEventListener('click', () => {
                signatureContent.value = '';
                signatureResult.value = '';
            });

            // 初始化显示请求设置信息
            updateRequestInfo();
        });

                // -------------------------- Server 核心逻辑（补全缺失部分） --------------------------
        let serverTabCount = 1; // 初始选项卡计数
        let activeServerInstances = {}; // 存储已启动的Server实例（tabId -> 服务状态）

        // 初始化第一个选项卡事件（DOM加载完成后执行）
        document.addEventListener('DOMContentLoaded', () => {
            // 1. 协议切换（显示/隐藏HTTPS证书上传）
            document.querySelector('.server-protocol[data-tab-id="tab-1"]').addEventListener('change', () => {
                toggleServerSSLConfig('tab-1');
            });

            // 2. 证书上传（转为Base64存储，避免后端读取文件问题）
            document.querySelector('.server-ssl-key[data-tab-id="tab-1"]').addEventListener('change', (e) => {
                readFileAsBase64(e.target, document.querySelector('.server-ssl-key-content[data-tab-id="tab-1"]'));
            });
            document.querySelector('.server-ssl-cert[data-tab-id="tab-1"]').addEventListener('change', (e) => {
                readFileAsBase64(e.target, document.querySelector('.server-ssl-cert-content[data-tab-id="tab-1"]'));
            });

            // 3. 初始选项卡点击切换
            document.querySelectorAll('.server-tab').forEach(tab => {
                tab.addEventListener('click', () => switchServerTab(tab.dataset.tabId));
            });

            // 4. "添加Server"按钮事件
            document.getElementById('add-server-tab').addEventListener('click', addServerTab);
        });

        // -------------------------- 1. 选项卡管理函数 --------------------------
        // 切换选项卡（激活状态切换）
        function switchServerTab(tabId) {
            // 切换选项卡导航激活状态
            document.querySelectorAll('.server-tab').forEach(tab => {
                tab.classList.toggle('active', tab.dataset.tabId === tabId);
                tab.classList.toggle('bg-primary', tab.dataset.tabId === tabId);
                tab.classList.toggle('text-white', tab.dataset.tabId === tabId);
                tab.classList.toggle('bg-gray-200', tab.dataset.tabId !== tabId);
                tab.classList.toggle('text-gray-700', tab.dataset.tabId !== tabId);
            });

            // 切换选项卡内容显示
            document.querySelectorAll('.server-tab-content').forEach(content => {
                content.classList.toggle('active', content.id === `${tabId}-content`);
                content.classList.toggle('hidden', content.id !== `${tabId}-content`);
                content.classList.toggle('block', content.id === `${tabId}-content`);
            });
        }

        // 添加新选项卡
        function addServerTab() {
            serverTabCount++;
            const tabId = `tab-${serverTabCount}`;
            const defaultPort = 8080 + serverTabCount - 1; // 自动分配端口（避免初始冲突）

            // -------------------------- 新增选项卡导航 --------------------------
            const tabNav = document.createElement('div');
            tabNav.className = 'server-tab px-4 py-2 rounded-t-lg bg-gray-200 text-gray-700 cursor-pointer';
            tabNav.dataset.tabId = tabId;
            tabNav.innerHTML = `
                Server ${serverTabCount}
                <button class="ml-2 text-gray-500 hover:text-gray-700" onclick="removeServerTab('${tabId}')">
                    <i class="fa fa-times"></i>
                </button>
            `;
            // 绑定选项卡切换事件
            tabNav.addEventListener('click', () => switchServerTab(tabId));
            document.getElementById('server-tabs').appendChild(tabNav);

            // -------------------------- 新增选项卡内容 --------------------------
            const tabContent = document.createElement('div');
            tabContent.className = 'server-tab-content hidden';
            tabContent.id = `${tabId}-content`;
            tabContent.innerHTML = `
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
                    <!-- 协议选择 -->
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">协议</label>
                        <select class="server-protocol w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="${tabId}">
                            <option value="http">HTTP</option>
                            <option value="https">HTTPS</option>
                        </select>
                    </div>
                    <!-- 端口输入 -->
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">端口 <span class="text-danger" id="port-error-${tabId}"></span></label>
                        <input type="number" min="1" max="65535" value="${defaultPort}" class="server-port w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="${tabId}" placeholder="输入端口号（1-65535）">
                    </div>
                </div>

                <!-- HTTPS证书配置（默认隐藏） -->
                <div class="server-ssl-config hidden mb-4" data-tab-id="${tabId}">
                    <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">SSL 私钥文件（.key）</label>
                            <input type="file" accept=".key" class="server-ssl-key w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="${tabId}">
                            <input type="hidden" class="server-ssl-key-content" data-tab-id="${tabId}">
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">SSL 证书文件（.cert/.pem）</label>
                            <input type="file" accept=".cert,.pem" class="server-ssl-cert w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="${tabId}">
                            <input type="hidden" class="server-ssl-cert-content" data-tab-id="${tabId}">
                        </div>
                    </div>
                    <p class="text-xs text-gray-500 mt-1">HTTPS模式需上传有效的SSL证书和私钥文件</p>
                </div>

                <!-- 响应路径 -->
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">响应路径（如 /api/data）</label>
                    <input type="text" value="/" class="server-path w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="${tabId}" placeholder="输入请求路径">
                </div>

                <!-- 响应状态码 -->
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">响应状态码</label>
                    <input type="number" min="100" max="599" value="200" class="server-status-code w-full bg-light border-0 rounded-lg px-4 py-2 font-medium text-dark focus:ring-2 focus:ring-primary/50 transition-all" data-tab-id="${tabId}" placeholder="输入状态码（100-599）">
                </div>

                <!-- 响应头配置 -->
                <div class="mb-4">
                    <div class="flex items-center justify-between mb-2 cursor-pointer" onclick="toggleServerHeaders('${tabId}')">
                        <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                            <i class="fa fa-header text-primary"></i>响应头
                        </h3>
                        <i class="fa fa-chevron-down text-gray-500 transition-transform duration-300" id="server-headers-icon-${tabId}"></i>
                    </div>
                    <div id="server-headers-container-${tabId}" class="max-h-60 overflow-y-auto scrollbar-thin bg-gray-50 p-3 rounded-lg border border-gray-200 space-y-2">
                        <div class="server-header-row flex gap-2">
                            <input type="text" placeholder="Key（如 Content-Type）" value="Content-Type" class="server-header-key flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm" data-tab-id="${tabId}">
                            <input type="text" placeholder="Value" value="application/json" class="server-header-value flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm" data-tab-id="${tabId}">
                            <button class="remove-server-header text-gray-400 hover:text-danger p-2 rounded hover:bg-red-50 transition-colors" onclick="removeServerHeader(this)">
                                <i class="fa fa-trash"></i>
                            </button>
                        </div>
                        <button class="add-server-header w-full py-2 text-primary border border-dashed border-primary/50 rounded-lg hover:bg-primary/5 transition-colors flex items-center justify-center gap-1 text-sm" onclick="addServerHeader('${tabId}')">
                            <i class="fa fa-plus"></i>添加响应头
                        </button>
                    </div>
                </div>

                <!-- 响应体配置 -->
                <div class="mb-4">
                    <div class="flex items-center justify-between mb-2">
                        <h3 class="font-semibold text-gray-800 flex items-center gap-2">
                            <i class="fa fa-file-text-o text-primary"></i>响应体
                        </h3>
                        <select class="server-body-type text-sm bg-light border-0 rounded px-2 py-1 focus:ring-2 focus:ring-primary/50" data-tab-id="${tabId}">
                            <option value="text">文本</option>
                            <option value="json" selected>JSON（推荐）</option>
                        </select>
                    </div>
                    <textarea class="server-body w-full h-40 p-3 bg-gray-50 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary/50 scrollbar-thin font-mono text-sm" data-tab-id="${tabId}" placeholder='示例：{"code":200,"data":"success"}'>{"code":200,"message":"success","data":{"id":${serverTabCount},"content":"test server response"}}</textarea>
                </div>

                <!-- 状态和控制按钮 -->
                <div class="flex items-center justify-between">
                    <div class="server-status text-sm px-3 py-2 rounded-full bg-gray-100 text-gray-600" id="server-status-${tabId}">
                        <i class="fa fa-circle-o text-gray-500"></i> 已停止
                    </div>
                    <div class="flex gap-2">
                        <button class="start-server bg-success hover:bg-success/90 text-white px-6 py-2 rounded-lg font-medium transition-all transform hover:scale-105 flex items-center gap-2" data-tab-id="${tabId}" onclick="startServer('${tabId}')">
                            <i class="fa fa-play"></i>启动
                        </button>
                        <button class="stop-server bg-danger hover:bg-danger/90 text-white px-6 py-2 rounded-lg font-medium transition-all transform hover:scale-105 flex items-center gap-2 hidden" data-tab-id="${tabId}" onclick="stopServer('${tabId}')">
                            <i class="fa fa-stop"></i>停止
                        </button>
                    </div>
                </div>
            `;
            document.getElementById('server-tab-contents').appendChild(tabContent);

            // -------------------------- 绑定新选项卡事件 --------------------------
            // 协议切换（显示/隐藏SSL配置）
            tabContent.querySelector(`.server-protocol[data-tab-id="${tabId}"]`).addEventListener('change', () => {
                toggleServerSSLConfig(tabId);
            });

            // 证书上传（转为Base64）
            tabContent.querySelector(`.server-ssl-key[data-tab-id="${tabId}"]`).addEventListener('change', (e) => {
                readFileAsBase64(e.target, tabContent.querySelector(`.server-ssl-key-content[data-tab-id="${tabId}"]`));
            });
            tabContent.querySelector(`.server-ssl-cert[data-tab-id="${tabId}"]`).addEventListener('change', (e) => {
                readFileAsBase64(e.target, tabContent.querySelector(`.server-ssl-cert-content[data-tab-id="${tabId}"]`));
            });

            // 自动切换到新选项卡
            switchServerTab(tabId);
        }

        // 删除选项卡（先停止服务，再删除DOM）
        function removeServerTab(tabId) {
            // 1. 若服务已启动，先停止
            if (activeServerInstances[tabId]) {
                stopServer(tabId, true); // true表示删除前停止
            }

            // 2. 删除选项卡导航和内容
            const tabNav = document.querySelector(`.server-tab[data-tab-id="${tabId}"]`);
            const tabContent = document.getElementById(`${tabId}-content`);
            if (tabNav) tabNav.remove();
            if (tabContent) tabContent.remove();

            // 3. 若删除的是最后一个选项卡，自动添加新选项卡
            const remainingTabs = document.querySelectorAll('.server-tab');
            if (remainingTabs.length === 0) {
                addServerTab();
            } else {
                // 切换到第一个剩余选项卡
                switchServerTab(remainingTabs[0].dataset.tabId);
            }
        }

        // -------------------------- 2. SSL配置显示/隐藏 --------------------------
        function toggleServerSSLConfig(tabId) {
            const protocol = document.querySelector(`.server-protocol[data-tab-id="${tabId}"]`).value;
            const sslConfig = document.querySelector(`.server-ssl-config[data-tab-id="${tabId}"]`);
            
            if (protocol === 'https') {
                sslConfig.classList.remove('hidden');
                sslConfig.classList.add('block', 'animate-fadeIn');
            } else {
                sslConfig.classList.add('hidden');
                sslConfig.classList.remove('block', 'animate-fadeIn');
            }
        }

        // -------------------------- 3. 文件读取为Base64（证书用） --------------------------
        function readFileAsBase64(fileInput, hiddenInput) {
            const file = fileInput.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = (e) => {
                // 提取Base64内容（去掉前缀 "data:application/octet-stream;base64,"）
                const base64Content = e.target.result.split(',')[1];
                hiddenInput.value = base64Content;
            };
            reader.readAsDataURL(file);
        }

        // -------------------------- 4. 响应头动态添加/删除 --------------------------
        // 展开/折叠响应头容器
        function toggleServerHeaders(tabId) {
            const container = document.getElementById(`server-headers-container-${tabId}`);
            const icon = document.getElementById(`server-headers-icon-${tabId}`);
            const isExpanded = container.style.maxHeight !== '0px';

            container.style.maxHeight = isExpanded ? '0px' : '240px';
            icon.style.transform = isExpanded ? 'rotate(-180deg)' : 'rotate(0deg)';
        }

        // 添加响应头行
        function addServerHeader(tabId) {
            const container = document.getElementById(`server-headers-container-${tabId}`);
            const addBtn = container.querySelector('.add-server-header');

            const headerRow = document.createElement('div');
            headerRow.className = 'server-header-row flex gap-2 animate-fadeIn';
            headerRow.innerHTML = `
                <input type="text" placeholder="Key（如 Content-Type）" class="server-header-key flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm" data-tab-id="${tabId}">
                <input type="text" placeholder="Value" class="server-header-value flex-1 px-3 py-2 rounded border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 text-sm" data-tab-id="${tabId}">
                <button class="remove-server-header text-gray-400 hover:text-danger p-2 rounded hover:bg-red-50 transition-colors" onclick="removeServerHeader(this)">
                    <i class="fa fa-trash"></i>
                </button>
            `;

            // 插入到"添加响应头"按钮前
            container.insertBefore(headerRow, addBtn);
        }

        // 删除响应头行
        function removeServerHeader(btn) {
            const row = btn.closest('.server-header-row');
            row.classList.add('opacity-0');
            setTimeout(() => row.remove(), 300);
        }

        // -------------------------- 5. Server启停核心逻辑（与后端交互） --------------------------
        // 启动Server
        async function startServer(tabId) {
            // 1. 收集当前选项卡配置
            const config = getServerConfig(tabId);
            if (!config) return; // 配置验证失败

            // 2. 检查端口是否已被占用（前端预校验）
            const portInUse = Object.values(activeServerInstances).some(instance => instance.port === config.port);
            if (portInUse) {
                showPortError(tabId, '端口已被其他Server占用，请更换端口');
                return;
            }

            // 3. 禁用启动按钮，防止重复点击
            const startBtn = document.querySelector(`.start-server[data-tab-id="${tabId}"]`);
            const stopBtn = document.querySelector(`.stop-server[data-tab-id="${tabId}"]`);
            const statusEl = document.getElementById(`server-status-${tabId}`);
            
            startBtn.disabled = true;
            statusEl.innerHTML = '<i class="fa fa-circle-o-notch fa-spin text-primary"></i> 启动中...';
            statusEl.className = 'server-status text-sm px-3 py-2 rounded-full bg-primary/10 text-primary';

            try {
                // 4. 调用后端接口启动Server（此处需替换为你的后端地址）
                const response = await fetch('http://localhost:3000/api/server/start', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ tabId, ...config })
                });

                const result = await response.json();
                if (result.success) {
                    // 5. 启动成功：更新状态和按钮
                    activeServerInstances[tabId] = {
                        port: config.port,
                        protocol: config.protocol,
                        serverId: result.serverId // 后端返回的服务唯一ID，用于停止
                    };

                    statusEl.innerHTML = `<i class="fa fa-circle text-success"></i> 运行中（${config.protocol}://localhost:${config.port}${config.path}）`;
                    statusEl.className = 'server-status text-sm px-3 py-2 rounded-full bg-success/10 text-success';
                    startBtn.classList.add('hidden');
                    stopBtn.classList.remove('hidden');
                    clearPortError(tabId);
                } else {
                    // 启动失败：恢复状态
                    statusEl.innerHTML = '<i class="fa fa-circle-o text-danger"></i> 启动失败';
                    statusEl.className = 'server-status text-sm px-3 py-2 rounded-full bg-danger/10 text-danger';
                    showPortError(tabId, result.message || '启动失败，请检查配置');
                }
            } catch (error) {
                // 网络错误：恢复状态
                statusEl.innerHTML = '<i class="fa fa-circle-o text-danger"></i> 连接后端失败';
                statusEl.className = 'server-status text-sm px-3 py-2 rounded-full bg-danger/10 text-danger';
                showPortError(tabId, '无法连接到后端服务，请确保后端已启动');
            } finally {
                // 恢复启动按钮可用
                startBtn.disabled = false;
            }
        }

        // 停止Server
        async function stopServer(tabId, isRemoving = false) {
            // 1. 检查服务是否已启动
            if (!activeServerInstances[tabId]) {
                if (!isRemoving) alert('服务未启动，无需停止');
                return;
            }

            // 2. 禁用停止按钮
            const startBtn = document.querySelector(`.start-server[data-tab-id="${tabId}"]`);
            const stopBtn = document.querySelector(`.stop-server[data-tab-id="${tabId}"]`);
            const statusEl = document.getElementById(`server-status-${tabId}`);
            
            stopBtn.disabled = true;
            statusEl.innerHTML = '<i class="fa fa-circle-o-notch fa-spin text-warning"></i> 停止中...';
            statusEl.className = 'server-status text-sm px-3 py-2 rounded-full bg-warning/10 text-warning';

            try {
                // 3. 调用后端接口停止Server
                const serverId = activeServerInstances[tabId].serverId;
                await fetch('http://localhost:3000/api/server/stop', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ tabId, serverId })
                });

                // 4. 停止成功：更新状态
                delete activeServerInstances[tabId];
                statusEl.innerHTML = '<i class="fa fa-circle-o text-gray-500"></i> 已停止';
                statusEl.className = 'server-status text-sm px-3 py-2 rounded-full bg-gray-100 text-gray-600';
                stopBtn.classList.add('hidden');
                startBtn.classList.remove('hidden');
                clearPortError(tabId);
            } catch (error) {
                // 停止失败
                statusEl.innerHTML = '<i class="fa fa-circle-o text-danger"></i> 停止失败';
                statusEl.className = 'server-status text-sm px-3 py-2 rounded-full bg-danger/10 text-danger';
                if (!isRemoving) alert('停止服务失败：' + error.message);
            } finally {
                stopBtn.disabled = false;
            }
        }

        // -------------------------- 6. 辅助函数（配置收集、验证） --------------------------
        // 收集当前选项卡的Server配置
        function getServerConfig(tabId) {
            // 协议和端口
            const protocol = document.querySelector(`.server-protocol[data-tab-id="${tabId}"]`).value;
            const port = parseInt(document.querySelector(`.server-port[data-tab-id="${tabId}"]`).value);
            
            // 端口验证
            if (isNaN(port) || port < 1 || port > 65535) {
                showPortError(tabId, '端口必须是1-65535之间的数字');
                return null;
            }

            // HTTPS证书（仅HTTPS需要）
            let sslKey = '';
            let sslCert = '';
            if (protocol === 'https') {
                sslKey = document.querySelector(`.server-ssl-key-content[data-tab-id="${tabId}"]`).value;
                sslCert = document.querySelector(`.server-ssl-cert-content[data-tab-id="${tabId}"]`).value;
                
                if (!sslKey || !sslCert) {
                    showPortError(tabId, 'HTTPS模式需上传SSL私钥和证书');
                    return null;
                }
            }

            // 响应路径、状态码
            const path = document.querySelector(`.server-path[data-tab-id="${tabId}"]`).value || '/';
            const statusCode = parseInt(document.querySelector(`.server-status-code[data-tab-id="${tabId}"]`).value);
            
            // 状态码验证
            if (isNaN(statusCode) || statusCode < 100 || statusCode > 599) {
                showPortError(tabId, '状态码必须是100-599之间的数字');
                return null;
            }

            // 响应头
            const headers = {};
            document.querySelectorAll(`.server-header-row[data-tab-id="${tabId}"]`).forEach(row => {
                const key = row.querySelector('.server-header-key').value.trim();
                const value = row.querySelector('.server-header-value').value.trim();
                if (key) headers[key] = value;
            });

            // 响应体（处理JSON格式）
            const bodyType = document.querySelector(`.server-body-type[data-tab-id="${tabId}"]`).value;
            let body = document.querySelector(`.server-body[data-tab-id="${tabId}"]`).value.trim();
            
            if (bodyType === 'json' && body) {
                try {
                    JSON.parse(body); // 验证JSON格式
                } catch (e) {
                    showPortError(tabId, '响应体JSON格式错误：' + e.message);
                    return null;
                }
            }

            // 清除之前的错误提示
            clearPortError(tabId);
            return { protocol, port, sslKey, sslCert, path, statusCode, headers, body };
        }

        // 显示端口错误提示
        function showPortError(tabId, message) {
            const errorEl = document.getElementById(`port-error-${tabId}`);
            errorEl.textContent = message;
            errorEl.style.display = 'inline';
        }

        // 清除端口错误提示
        function clearPortError(tabId) {
            const errorEl = document.getElementById(`port-error-${tabId}`);
            errorEl.textContent = '';
            errorEl.style.display = 'none';
        }
    </script>
</body>
</html>